package com.zj.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zj.dao.CategoryMapper;
import com.zj.model.Banner;
import com.zj.model.Category;
import com.zj.restApi.FileUploadApi;
import com.zj.restApi.IdGenratorApi;
import com.zj.web.bean.BannerDTO;
import com.zj.web.bean.CategoryDTO;
import com.zj.web.bean.ResponseResult;
import lombok.AllArgsConstructor;
import lombok.extern.java.Log;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
@Log
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService{
    private final CategoryMapper categoryMapper;
    //方案三：利用Feign客户端
    @Autowired
    private IdGenratorApi idGenratorApi;
    @Autowired
    private FileUploadApi fileUploadApi;
    @Override
    @Transactional
//    //当新增货修改了种类时，需要清楚所有相关的缓存
//    //“categories” :是缓存的名称
//    //allEntries = true : 表示清除所有的缓存
    @CacheEvict(value = "categories",allEntries = true) //添加缓存清除
    public CategoryDTO addCategory(CategoryDTO categoryDTO) {
        //1.调用 idGenerator 服务 取出id号
        ResponseEntity<ResponseResult<Long>> responseEntity = idGenratorApi.getNextId();  //jdk动态代理对象
        if(responseEntity.getStatusCode()!= HttpStatus.OK || responseEntity.getBody()==null){
            throw new RuntimeException("调用idGenerator服务失败");
        }
        ResponseResult<Long> responseResult = responseEntity.getBody();
        log.info(responseResult.toString());
        if (responseResult == null || responseResult.getCode() != 1) {
            throw new RuntimeException("调用idGenerator服务失败");
        }
        Long id = responseResult.getData();
        categoryDTO.setCategoryId(id);

//        文件上传  利用Feign客户端
        ResponseEntity<ResponseResult> responseEntity1 = this.fileUploadApi.uploadFile(new MultipartFile[]{categoryDTO.getIcoImgFile()});
        if(responseEntity1.getStatusCode()!= HttpStatus.OK || responseEntity1.getBody()==null){
            throw new RuntimeException("调用fileUpload服务失败");
        }
        ResponseResult responseResult1 = responseEntity1.getBody();
        log.info(responseResult1.toString());
        if (responseResult1 == null || responseResult1.getCode() != 1) {
            throw new RuntimeException("调用fileUpload服务失败");
        }
        List<String> urls=(List<String>) responseResult1.getData();
        categoryDTO.setIcon( urls.get(0) );
        categoryDTO.setCategoryStatus(CATEGORY_STATUS_NORMAL);

        // 3. 将 CategoryDTO 转换为 Category 实体对象
        Category category = new Category();
        // 使用 Spring 的 BeanUtils 拷贝同名属性
        // 这会将 categoryDTO 中与 category 属性名相同且类型兼容的值拷贝过去
        //                      categoryDTO   category Model
        BeanUtils.copyProperties(categoryDTO, category);

        // 特别注意：如果有一些特殊字段需要手动处理，在这里设置
        // 例如，Banner 实体里没有 imageFile 字段，但 BannerDTO 有。
        // BeanUtils.copyProperties 会忽略 banner 中不存在的字段，所以是安全的。
        // banner.setSomeField(bannerDTO.getSomeSpecialField());

        // 4. 执行数据库插入操作，传入的是 Banner 实体对象
        Boolean flag = this.save(category);
        if(!flag){
            throw new RuntimeException("添加失败");
        }

        return categoryDTO;
    }

    //根据状态查询分类信息
    @Override
    //启用缓存：
    //value="banners" : 缓存的名称，所有轮播图相关的缓存都存放在这个命名空间下
    //key="#bannerStatus!=null ? 'status_'+#bannerStatus : 'all'" : 缓存的key，这里使用bannerStatus作为key，因为根据状态查询轮播图是一个固定的操作，所以可以缓存
    //  - 如果bannerStatus为null，缓存的key为"all"，表示查询所有轮播图
    //  - 如果bannerStatus不为null，缓存的key为"status_"+bannerStatus，例如status_1表示查询状态为1的轮播图
    //这个策略可以区分不同状态的轮播图列表，同时也有一个缓存所有轮播图的入口，例如status_1和status_2的轮播图是不同的，所以可以缓存
    //key使用了spring el表达式，根据bannerStatus是否为null来动态生成key
    //condition="#bannerStatus != null" : 缓存的条件，只有当bannerStatus不为null时才缓存
    @Cacheable(value = "categories", keyGenerator = "categoryKeyGenerator")
    public List<CategoryDTO> getCategories(Integer categoryStatus) {
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        if (categoryStatus!=null && categoryStatus!=-1){
            queryWrapper.eq(Category::getCategoryStatus, categoryStatus);
        }
        queryWrapper.orderByDesc(Category::getCategoryStatus);
        List<Category> categories = categoryMapper.selectList(queryWrapper);
        //类型转换 Category Model 转成 Category DTO
        return categories.stream().map(category -> {
            CategoryDTO categoryDTO = new CategoryDTO();
            BeanUtils.copyProperties(category, categoryDTO);
            return categoryDTO;
        }).collect(Collectors.toList());
    }


    //根据分类id查询分类信息
    @Override
    @Cacheable(value = "categories", key = "#categoryId")
    public CategoryDTO getCategoryById(Long categoryId) {
        //mybatis plus 中的自带根据id查询语句
        Category category = categoryMapper.selectById(categoryId);
        if(category==null){
            throw new RuntimeException("分类不存在"+categoryId);
        }
        CategoryDTO categoryDTO = new CategoryDTO();
        BeanUtils.copyProperties(category, categoryDTO);
        return categoryDTO;
    }

    //根据id修改类别的状态
    @Override
    @Transactional
    @CacheEvict(value = "categories",allEntries = true) //添加缓存清除
    public CategoryDTO updateCategoryStatus(Long categoryId, Integer category_status) {
        //判断分类是否存在
        Category category = categoryMapper.selectById(categoryId);
        if(category==null){
            throw new RuntimeException("分类不存在"+categoryId);
        }
        category.setCategoryStatus(category_status);
        categoryMapper.updateById(category);
        CategoryDTO categoryDTO = new CategoryDTO();
        BeanUtils.copyProperties(category, categoryDTO);
        return categoryDTO;
    }

    //更新分类信息
    @Override
    @Transactional
    @CacheEvict(value = "categories",allEntries = true) //添加缓存清除
    public CategoryDTO updateCategory(CategoryDTO category) {
        //判断分类是否存在
        Category category1 = categoryMapper.selectById(category.getCategoryId());
        if(category1==null){
            throw new RuntimeException("分类不存在"+category.getCategoryId());
        }
        //更新分类信息
        if (category.getIcoImgFile()!=null){
            //文件上传  利用Feign客户端
            ResponseEntity<ResponseResult> responseEntity1 = this.fileUploadApi.uploadFile(new MultipartFile[]{category.getIcoImgFile()});
            if(responseEntity1.getStatusCode()!= HttpStatus.OK || responseEntity1.getBody()==null){
                throw new RuntimeException("调用fileUpload服务失败");
            }
            ResponseResult responseResult1 = responseEntity1.getBody();
            log.info(responseResult1.toString());
            if (responseResult1 == null || responseResult1.getCode() != 1) {
                throw new RuntimeException("调用fileUpload服务失败");
            }
            List<String> urls=(List<String>) responseResult1.getData();
            category.setIcon( urls.get(0) );
        }

        System.out.println("==============我的值+++++++++++++=="+category);
        BeanUtils.copyProperties(category,category1);
        categoryMapper.updateById(category1);
        //返回更新后的分类信息
        CategoryDTO categoryDTO = new CategoryDTO();
        BeanUtils.copyProperties(category1, categoryDTO);
        return categoryDTO;
    }
}
